﻿
#include "MatrixBuffer.h"
#include <memory>

MatrixBuffer* MatrixBuffer::create(GLuint semantic, unsigned int count, GLenum usage/* = GL_STATIC_DRAW*/)
{
    auto result = new (std::nothrow) MatrixBuffer();

    if (result && result->init(semantic, sizeof(ESMatrix) * count, usage))
    {
        return result;
    }

    if (result)
    {
        delete result;
    }

    return nullptr;
}

MatrixBuffer::MatrixBuffer()
: _vbo(0)
, _semantic(0)
, _size(0)
, _usage(0)
{

}

MatrixBuffer::~MatrixBuffer()
{
    if (glIsBuffer(_vbo))
    {
        glDeleteBuffers(1, &_vbo);
        _vbo = 0;
    }
}

bool MatrixBuffer::init(GLint semantic, int size, GLenum usage/* = GL_STATIC_DRAW*/)
{
    _semantic = semantic;
    _size = size;
    _usage = usage;
    
    glGenBuffers(1, &_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferData(GL_ARRAY_BUFFER, _size, nullptr, _usage);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    return true;
}

void MatrixBuffer::updateMatrix(const void* matrix, unsigned int pos)
{
    if ((pos + 1) * sizeof(ESMatrix) > _size)
    {
        return;
    }

    glBindBuffer(GL_ARRAY_BUFFER, _vbo);

    // 此操作返回GPU存储缓冲区的地址空间指针
    ESMatrix* buffer = (ESMatrix*)glMapBufferRange(GL_ARRAY_BUFFER, 0, _size, GL_MAP_WRITE_BIT);
    memcpy(&buffer[pos], matrix, sizeof(ESMatrix));
    glUnmapBuffer(GL_ARRAY_BUFFER);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

GLuint MatrixBuffer::getVBO() const
{
    return _vbo;
}

void MatrixBuffer::use()
{
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);

    for (GLuint i = 0; i < 4; i++)
    {
        // 开启顶点数组模式:索引
        glEnableVertexAttribArray(_semantic + i);

        // 设置:索引、向量元素个数、数值类型、是否规范化、向量之间的跨距、起始位置
        glVertexAttribPointer(_semantic + i, 4, GL_FLOAT, GL_FALSE, sizeof(ESMatrix),
            (const void*)(sizeof(GLfloat) * i * 4));

        // 几个模型变换一次:索引、模型间隔
        glVertexAttribDivisor(_semantic + i, 1);
    }
}